#ifndef SCREEN_H
#define SCREEN_H

#include <TFT_eSPI.h>
#include <Arduino.h>
#include <TJpg_Decoder.h>
#include "../globals.h"
#include "../logger.h"
#include "../assets/logo_jpg.h"

static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 240;

TFT_eSPI tft = TFT_eSPI(); /* TFT instance */

inline void set_brightness(int _brightness, bool remenber=true){
   if (_brightness < 255 && _brightness > 5){
      // analogWriteFreq(10000);
      analogWrite(PIN_BLK, _brightness);
      if (remenber) {brightness = _brightness;}
      
   // }else if(_brightness >= 255) {analogWrite(SCREEN_BL_PIN, 255); brightness=255;
   }else if(_brightness >= 255) 
    {
        digitalWrite(PIN_BLK, HIGH);
        if (remenber){brightness = _brightness;}
   }else if(_brightness <= 5)
   {
    analogWrite(PIN_BLK, 5); 
    if(remenber){brightness = _brightness;}
   }
}

// 平滑的亮起
void smooth_on(){
   digitalWrite(PIN_BLK, LOW);
   // analogWriteFreq(10000);
   for(int i=0; i<brightness; i++){
      // analogWrite(SCREEN_BL_PIN, i);
      set_brightness(i, false);
      delay(2);
   }
}

void smooth_off(){
   analogWrite(PIN_BLK, brightness);
   // analogWriteFreq(10000);
   for(int i=brightness; i>=0; i--){
      analogWrite(PIN_BLK, i);
      delay(2);
   }
}

uint16_t* logoBuffer1 = nullptr; // Toggle buffer for 16*16 MCU block
uint16_t* logoBuffer2 = nullptr; // Toggle buffer for 16*16 MCU block
uint16_t* logoBufferPtr = logoBuffer1;
bool logoBufferSel = 0;
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap){
   // Stop further decoding as image is running off bottom of screen
  if ( y >= tft.height() ) return 0;
  if (logoBufferSel) logoBufferPtr = logoBuffer2;
  else logoBufferPtr = logoBuffer1;
  logoBufferSel = !logoBufferSel; // Toggle buffer selection
  //  pushImageDMA() will clip the image block at screen boundaries before initiating DMA
  tft.pushImageDMA(x, y, w, h, bitmap, logoBufferPtr); // Initiate DMA - blocking only if last DMA is not complete
  // The DMA transfer of image block to the TFT is now in progress...
  // Return 1 to decode next block.
  return 1;
}


void render_logo(){
   // 动态分配内存
    logoBuffer1 = (uint16_t*)malloc(16 * 16 * sizeof(uint16_t));
    logoBuffer2 = (uint16_t*)malloc(16 * 16 * sizeof(uint16_t));

    if (logoBuffer1 == nullptr || logoBuffer2 == nullptr) {
        // 内存分配失败，处理错误
        if (logoBuffer1) free(logoBuffer1);
        if (logoBuffer2) free(logoBuffer2);
        return;
    }
   tft.fillScreen(TFT_BLACK);
   TJpgDec.setJpgScale(1);
   TJpgDec.setCallback(tft_output);
   uint16_t w = 0, h = 0;
   TJpgDec.getJpgSize(&w, &h, logo, sizeof(logo));
   tft.startWrite();
   TJpgDec.drawJpg(0, 0, logo, sizeof(logo));
   tft.endWrite();
   // 释放内存
   free(logoBuffer1);
   free(logoBuffer2);
   logoBuffer1 = nullptr;
   logoBuffer2 = nullptr;
}

void screen_element_prepare(){ 
    tft.fillScreen(TFT_YELLOW);
}

void screen_init(){
    logln("Initializing screen...");
    pinMode(PIN_BLK, OUTPUT);
    pinMode(PIN_SCREEN_VDD, OUTPUT);
    digitalWrite(PIN_BLK, LOW);
    digitalWrite(PIN_SCREEN_VDD, LOW);
    tft.init();
    tft.setRotation(1); /* Landscape orientation, flipped */
    tft.setSwapBytes(true);
    tft.initDMA();
    logln("Screen powerd on.");
    render_logo();
    delay(300);
    smooth_on();
    logf("Logo rendered %d\n", brightness);
    delay(500);
    smooth_off();
    screen_element_prepare();
    smooth_on();
}


void screen_update(){
    delay(1000);
    tft.fillScreen(TFT_BLUE);
    delay(1000);
    tft.fillScreen(TFT_RED);
    delay(1000);
    tft.fillScreen(TFT_YELLOW);
    logln("Screen looped.");
}

#endif // SCREEN_H